/**
 * @file nd03b_dev.c
 * @author yan.huang
 * @brief ND03B device setting functions
 * @version 1.x.x
 * @date 2022-02
 * 
 * @copyright Copyright (c) 2022, Shenzhen Nephotonics Inc.
 * 
 */

/** 
 @mainpage  ND03B_SDK
 <table>
 <tr><th>Project  <td>ND03B_SDK 
 <tr><th>Author   <td>yan.huang
 <tr><th>Date     <td>2022-02
 </table>
 @section   项目详细描述
 此项目基于ND03B模组进行开发的全功能SDK，<br/>

 
 @section	包含功能
 -#	模组的各种配置功能
 -#	模组两种标定功能
 -# 模组的测距功能

 @section   SDK版本 
 <table>
 <tr><th>Date              <th>S_Version      <th>Author              <th>Description  </tr>
 <tr><td>2022/02    	   <td>V0.0.1         <td>yan.huang           <td>创建初始版本 </tr>
 <tr><td>2022/03    	   <td>V0.0.2         <td>yan.huang           <td>延长等待数据时间 </tr>    
 <tr><td>2022/05    	   <td>V1.0.1         <td>yan.huang           <td>
 -# 删减无用函数
 -# 修改非线性标定流程 
 -# 新增带间隔时间测距接口
 -# 新增测量间隔时间设置和获取接口
 -# 新增doc目录用来存放相关文档
 -# 修改example目录下的例程代码
 -# 修改README文档
 </tr>   
 <tr><td>2022/05    	   <td>V1.0.2         <td>yan.huang           <td>
 -# 加入模组断电判断，修复重复退出ESD保护死机问题
 -# 修复设置曝光值失败问题
 </tr>   
 <tr><td>2022/07    	   <td>V1.0.3         <td>yan.huang           <td>
 -# 删除无用函数接口与寄存器
 -# 修改offset标定接口相关函数名称
 -# 修改部分寄存器名称
 </tr>   
  <tr><td>2022/08    	   <td>V1.0.4         <td>yan.huang           <td>
 -# 新增存储当前电压值接口
 -# 新增获取GPIO0电平状态函数指针
 -# 标定时将模组当前电压存到Flash
 -# 简化模组初始化步骤,并根据GPIO0电平状态变化获取测距信息
 -# 修改example目录下的单次测距例程
 -# 更改文件名及函数前缀,以ND03B开头
 -# 更新ND03B开发指南
  <tr><td>2022/08    	   <td>V1.0.5         <td>yan.huang           <td>
 -# 新增获取模组时钟频率寄存器
 -# 新增深度滤波接口
 -# 新增设置和获取滤波系数接口
 -# 新增设置和获取检测目标阈值接口
 -# 新增设置和获取低幅度阈值接口
  <tr><td>2022/10    	   <td>V1.0.6         <td>yan.huang           <td>
   -# 新增串扰标定(可设置标定距离)接口
   -# 新增offset标定(可设置标定距离)接口
   -# 可兼容51平台等八位机
   -# 调整部分寄存器兼容新固件
   -# 新增低功耗模式触发、高精度模式触发、自动检测模式触发接口
 </tr>   
  <tr><td>2022/10    	   <td>V1.0.7         <td>tongsheng.tang           <td>
   -# 去掉延迟。
   -# 修改一些宏定义配置，降低IIC通信时的功耗。
   -# 修改标定时设置标定距离是非0时才更新标定距。
   -# 修改一些宏定义名字。
   -# 关闭打印。
 </tr>   
  <tr><td>2022/11    	   <td>V1.0.8         <td>tongsheng.tang           <td>
   -# 修改ND03B_GetRangingData函数，去掉等待以及读取数据后进入休眠。
 </tr>   
  <tr><td>2022/12    	   <td>V1.0.9         <td>tongsheng.tang           <td>
   -# 新增装机测试代码示例。
   -# 新增幅度值过低时输出无效深度值。
   -# 新增获取串扰幅度值的函数。
   -# 修改默认串扰标定距离。
 </tr>   
  <tr><td>2022/12    	   <td>V1.0.10        <td>tongsheng.tang           <td>
   -# 新增设置灵敏度函数。
 </tr>   
 </table>
*/


#include "nd03b_comm.h"
#include "nd03b_dev.h"
#include "nd03b_data.h"
#include "nd03b_calib.h"
#include "nd03b_def.h"


/** SDK主版本 */
static uint8_t sdk_version_major = 1;
/** SDK次版本 */
static uint8_t sdk_version_minor = 0;
/** SDK小版本 */
static uint8_t sdk_version_patch = 10;


/**
 * @brief ND03B Get SDK Version
 *        获取当前SDK的软件版本号
 * @return  uint32_t   
 * @retval  软件版本号
 */
uint32_t ND03B_GetSdkVersion(void)
{
    return (uint32_t)sdk_version_major * 10000 + (uint32_t)sdk_version_minor * 100 + (uint32_t)sdk_version_patch;
}

/**
 * @brief ND03B Get Current Exposure
 *        获取当前ND03B的积分时间
 * @param   pNxDevice   模组设备
 * @return  uint32_t    当前积分时间/us
 */
uint16_t ND03B_GetCurrentExp(ND03B_Dev_t *pNxDevice)
{
    int32_t     ret = ND03B_ERROR_NONE;
    uint32_t    rbuf;
    uint16_t    current_exp = 0;

    ret = ND03B_ReadWord(pNxDevice, ND03B_REG_EXP_THERM, &rbuf);
    if(ND03B_ERROR_NONE == ret){
        current_exp = (rbuf >> 16) & 0xFFFF;
    }

	return current_exp;
}

/**
 * @brief ND03B Set Range Interval
 *        设置ND03B的测量间隔时间
 * @param   pNxDevice   模组设备
 * @param   interval    间隔时间/ms
 * @return  int32_t    
 */
int32_t ND03B_SetRangeInterval(ND03B_Dev_t *pNxDevice, uint32_t interval)
{
    int32_t ret = ND03B_ERROR_NONE;

    pNxDevice->config.range_interval = interval;

    return ret;
}

/**
 * @brief ND03B Get Range Interval
 *        获取ND03B的测量间隔时间
 * @param   pNxDevice   模组设备
 * @return  uint32_t    间隔时间
 */
uint32_t ND03B_GetRangeInterval(ND03B_Dev_t *pNxDevice)
{
    return pNxDevice->config.range_interval;
}

/**
 * @brief ND03B Save Low Power Data Request
 *        发送保存ND03B低功耗数据请求
 * @param   pNxDevice 模组设备
 * @return  int32_t   
 */
int32_t ND03B_SaveLowPowerDataRequest(ND03B_Dev_t *pNxDevice)
{
    int32_t     ret = ND03B_ERROR_NONE;

    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_DATA_VAL_REQ, ND03B_SAVE_LOW_POWER_DATA_REQ_MASK); 

    return ret;
}

/**
 * @brief ND03B Wait for Save Low Power Data
 *        等待ND03B低功耗数据保存完成
 * @param   pNxDevice 模组设备
 * @return  int32_t   
 */
int32_t ND03B_WaitforSaveLowPowerData(ND03B_Dev_t *pNxDevice)
{
	int32_t     ret = ND03B_ERROR_NONE;
	uint32_t    data_val_flag = 0;
    uint16_t    retry_cnt = 100;
	
    while(retry_cnt)
    {
		ret |= ND03B_ReadWord(pNxDevice, ND03B_REG_DATA_VAL_REQ, &data_val_flag);
        if(ND03B_SAVE_LOW_POWER_DATA_VAL_MASK == (data_val_flag & ND03B_SAVE_LOW_POWER_DATA_VAL_MASK))
            break;
		ND03B_Delay1ms(10);
        retry_cnt--;
	}

    if(retry_cnt == 0)
    {
        NX_PRINTF("Save Data Error\r\n");
        return ND03B_ERROR_TIME_OUT;
    }

    /* 清除有效位 */
    data_val_flag = data_val_flag & (~ND03B_SAVE_LOW_POWER_DATA_VAL_MASK);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_DATA_VAL_REQ, data_val_flag);

    return ret;
}

/**
 * @brief ND03B Low Power Data 
 *        发送保存低功耗数据
 * @param   pNxDevice 模组设备
 * @return  int32_t   
 */
int32_t ND03B_SaveLowPowerData(ND03B_Dev_t *pNxDevice)
{
    int32_t     ret = ND03B_ERROR_NONE;

    /*< 发送请求 >*/
    ret |= ND03B_SaveLowPowerDataRequest(pNxDevice);
    /* 等待完成 */
    ret |= ND03B_WaitforSaveLowPowerData(pNxDevice);

    return ret;
}

/**
 * @brief ND03B Set Sensitivity 
 *        设置低功耗阈值灵敏度
 * @param   pNxDevice 模组设备
 * @param   Sensitivity 灵敏度(1~100)
 * @return  int32_t   
 */
int32_t ND03B_SetSensitivity(ND03B_Dev_t *pNxDevice, uint32_t Sensitivity)
{
	int32_t     ret  = ND03B_ERROR_NONE; 
	uint32_t 	range[6] = {70, 100, 200, 500, 1000, 65535};
	uint32_t 	coe[6] = {0, 2, 2, 2, 2, 2};
    uint32_t 	threshold[6] = {60, 120, 90, 45, 20, 10};
	uint32_t 	data_th[6];
	int32_t 	i;

	ret |= ND03B_WaitDeviceBootUp(pNxDevice);
    ret |= ND03B_GetFirmwareVersion(pNxDevice, &pNxDevice->chip_info.nd03b_fw_version);
	Sensitivity = Sensitivity > 100 ? 100 : (0 ? 1 : Sensitivity);
	for(i = 0; i < sizeof(data_th)/sizeof(data_th[0]); i++)
    {
        threshold[i] = ((threshold[i]*100/Sensitivity));
        if(pNxDevice->chip_info.nd03b_fw_version == 10203)
            threshold[i] = threshold[i] / 10;
		data_th[i] = (coe[i]<<24) | (range[i]<<8) | threshold[i];
	}
	ret |= ND03B_WriteNWords(pNxDevice, ND03B_REG_LOW_POWER_TH, data_th, i);
	ret |= ND03B_SaveLowPowerData(pNxDevice);
	ND03B_SetXShutPinLevel(pNxDevice, 0);

	return ret;
}

/**
 * @brief ND03B Sleep
 *        ND03B待机
 * @param pNxDevice: ND03B模组设备信息结构体
 * @return int32_t
*/
int32_t ND03B_Sleep(ND03B_Dev_t *pNxDevice)
{
    int32_t     ret = ND03B_ERROR_NONE;

    ND03B_SetXShutPinLevel(pNxDevice, 0);
  
    return ret;
}

/**
 * @brief ND03B Wakeup
 *        唤醒ND03B
 * @param pNxDevice: ND03B模组设备信息结构体
 * @return int32_t
*/
int32_t ND03B_Wakeup(ND03B_Dev_t *pNxDevice)
{
    int32_t     ret = ND03B_ERROR_NONE;

    ND03B_SetXShutPinLevel(pNxDevice, 1);
    ret |= ND03B_WaitDeviceBootUp(pNxDevice);
    ret |= ND03B_InitDevice(pNxDevice);

    return ret;
}


/**
 * @brief ND03B InitDevice
 *        初始化设备
 * @param   pNxDevice   模组设备
 * @return  int32_t
 */
int32_t ND03B_InitDevice(ND03B_Dev_t *pNxDevice)
{
	int32_t     ret = ND03B_ERROR_NONE;

    NX_PRINTF("ND03B_InitDevice Start!\r\n");

    /** 停止测量 */
    ret |= ND03B_StopMeasurement(pNxDevice);
    /** 获取设备信息 */
	ret |= ND03B_GetDevInfo(pNxDevice);

    NX_PRINTF("ND03B_InitDevice End!\r\n");

	return ret;
}

/**
 * @brief ND03B Get Firmware Version 
 *        获取ND03B模组固件版本号
 * @param   pNxDevice   模组设备
 * @param   pFirmwareDataBuf  固件版本数据指针
 * @return  int32_t   
 */
int32_t ND03B_GetFirmwareVersion(ND03B_Dev_t *pNxDevice, uint32_t* pFirmwareDataBuf)
{
	int32_t     ret = ND03B_ERROR_NONE;

    ret |= ND03B_ReadWord(pNxDevice, ND03B_REG_FW_VERSION, pFirmwareDataBuf);

	return ret;
}

/**
 * @brief ND03B Low Power Mode Trig 
 *        ND03B低功耗模式触发
 * @param   pNxDevice   模组设备
 * @return  ND03B_ERROR_NONE:成功
 *          ND03B_ERROR_BOOT:启动失败--请检测模组是否焊接好，还有i2c地址与读写函数是否错误。
 */
int32_t ND03B_LowPowerModeTrig(ND03B_Dev_t *pNxDevice)
{
    int32_t     ret = ND03B_ERROR_NONE;

    NX_PRINTF("%s Start!\r\n", __func__);

    /* 重启 */
    ND03B_SetXShutPinLevel(pNxDevice, 0);
	ND03B_Delay10us(2);
    ND03B_SetXShutPinLevel(pNxDevice, 1);
	ND03B_Delay10us(50);

    ret |= ND03B_WriteByte(pNxDevice, ND03B_REG_BOOT1, ND03B_REG_BOOT1_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT2, ND03B_REG_BOOT2_VALUE);
    ND03B_Delay10us(30);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT3, ND03B_REG_BOOT3_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT4, ND03B_REG_BOOT4_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT5, ND03B_REG_BOOT5_VALUE);    
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_STATE, ND03B_LOW_POWER_MODE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT6, ND03B_REG_BOOT6_VALUE);
  
	if(ND03B_ERROR_NONE != ret)
    {
        NX_PRINTF("ND03B boot error\r\n");

        return ND03B_ERROR_BOOT;
    }
    
    NX_PRINTF("%s End!\r\n", __func__);

    return ND03B_ERROR_NONE;
}

/**
 * @brief ND03B High Range Mode Trig 
 *        ND03B模组高精度模式触发
 * @param   pNxDevice   模组设备
 * @return  ND03B_ERROR_NONE:成功
 *          ND03B_ERROR_BOOT:启动失败--请检测模组是否焊接好，还有i2c地址与读写函数是否错误。
 */
int32_t ND03B_HighRangingModeTrig(ND03B_Dev_t *pNxDevice)
{
    int32_t     ret = ND03B_ERROR_NONE;

    NX_PRINTF("%s Start!\r\n", __func__);

    /* 重启 */
    ND03B_SetXShutPinLevel(pNxDevice, 0);
	ND03B_Delay10us(2);
    ND03B_SetXShutPinLevel(pNxDevice, 1);
	ND03B_Delay10us(50);

    ret |= ND03B_WriteByte(pNxDevice, ND03B_REG_BOOT1, ND03B_REG_BOOT1_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT2, ND03B_REG_BOOT2_VALUE);
    ND03B_Delay10us(30);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT3, ND03B_REG_BOOT3_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT4, ND03B_REG_BOOT4_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT5, ND03B_REG_BOOT5_VALUE);    
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_STATE, ND03B_HIGH_RANGE_MODE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT6, ND03B_REG_BOOT6_VALUE);
  
	if(ND03B_ERROR_NONE != ret)
    {
        NX_PRINTF("ND03B boot error\r\n");

        return ND03B_ERROR_BOOT;
    }
    
    NX_PRINTF("%s End!\r\n", __func__);

    return ND03B_ERROR_NONE;
}

/**
 * @brief ND03B Auto Detect Mode Trig 
 *        ND03B自动检测模式触发
 * @param   pNxDevice   模组设备
 * @return  ND03B_ERROR_NONE:成功
 *          ND03B_ERROR_BOOT:启动失败--请检测模组是否焊接好，还有i2c地址与读写函数是否错误。
 */
int32_t ND03B_AutoDetectModeTrig(ND03B_Dev_t *pNxDevice)
{
    int32_t     ret = ND03B_ERROR_NONE;

    NX_PRINTF("%s Start!\r\n", __func__);

    /* 重启 */
    ND03B_SetXShutPinLevel(pNxDevice, 0);
	ND03B_Delay10us(2);
    ND03B_SetXShutPinLevel(pNxDevice, 1);
	ND03B_Delay10us(50);

    ret |= ND03B_WriteByte(pNxDevice, ND03B_REG_BOOT1, ND03B_REG_BOOT1_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT2, ND03B_REG_BOOT2_VALUE);
    ND03B_Delay10us(30);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT3, ND03B_REG_BOOT3_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT4, ND03B_REG_BOOT4_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT5, ND03B_REG_BOOT5_VALUE);     
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_STATE, ND03B_AUTO_DETECT_MODE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT6, ND03B_REG_BOOT6_VALUE);
  
	if(ND03B_ERROR_NONE != ret)
    {
        NX_PRINTF("ND03B boot error\r\n");

        return ND03B_ERROR_BOOT;
    }
    
    NX_PRINTF("%s End!\r\n", __func__);

    return ND03B_ERROR_NONE;
}

/**
 * @brief ND03B Get Device Information 
 *        获取设备当前信息
 * @param   pNxDevice   模组设备
 * @return  void   
 */
int32_t ND03B_GetDevInfo(ND03B_Dev_t *pNxDevice)
{
    int32_t     ret = ND03B_ERROR_NONE;
//    uint32_t    rbuf;

    /** 读取ND03B模组固件版本号 */
	ret |= ND03B_GetFirmwareVersion(pNxDevice, &pNxDevice->chip_info.nd03b_fw_version);
	NX_PRINTF("FwVersion: V%d.%d.%d\r\n", pNxDevice->chip_info.nd03b_fw_version/10000, pNxDevice->chip_info.nd03b_fw_version/100%100,pNxDevice->chip_info.nd03b_fw_version%100);
    
    return ret;
}

/**
 * @brief ND03B Wait for Device Boot Up 
 *        等待ND03B模组启动
 * @param   pNxDevice   模组设备
 * @return  ND03B_ERROR_NONE:成功
 *          ND03B_ERROR_BOOT:启动失败--请检测模组是否焊接好，还有i2c地址与读写函数是否错误。
 */
int32_t ND03B_WaitDeviceBootUp(ND03B_Dev_t *pNxDevice)
{
    int32_t     ret = ND03B_ERROR_NONE;
    int32_t     try_times = 200;

    NX_PRINTF("%s Start!\r\n", __func__);

    /* 重启 */
    ND03B_SetXShutPinLevel(pNxDevice, 0);
	ND03B_Delay10us(2);
    ND03B_SetXShutPinLevel(pNxDevice, 1);
	ND03B_Delay10us(50);

    ret |= ND03B_WriteByte(pNxDevice, ND03B_REG_BOOT1, ND03B_REG_BOOT1_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT2, ND03B_REG_BOOT2_VALUE);
    ND03B_Delay10us(30);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT3, ND03B_REG_BOOT3_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT4, ND03B_REG_BOOT4_VALUE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT5, ND03B_REG_BOOT5_VALUE);    
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_STATE, ND03B_NORMAL_MODE);
    ret |= ND03B_WriteWord(pNxDevice, ND03B_REG_BOOT6, ND03B_REG_BOOT6_VALUE);

    ND03B_Delay1ms(5);

    do{
        ND03B_Delay10us(50);
        ret |= ND03B_ReadWord(pNxDevice, ND03B_REG_STATE, &pNxDevice->dev_pwr_state);
    }
    while((pNxDevice->dev_pwr_state != ND03B_STATE_SOFTWARE_READY && pNxDevice->dev_pwr_state != ND03B_STATE_GOT_DEPTH) && --try_times) ;
  
	if((ND03B_ERROR_NONE != ret) || (0 == try_times))
    {
        NX_PRINTF("ND03B boot error\r\n");

        return ND03B_ERROR_BOOT;
    }
    
    NX_PRINTF("%s End!\r\n", __func__);

    return ND03B_ERROR_NONE;
}
